/*
  flamingo - 2D Game Engine
  Copyright (C) 2009 Bradley Zeis

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.

  Bradley Zeis
  bradzeis@gmail.com
*/

/* -------- UTILITY -------- */
int _is_left(Vector *v1, Vector *v2, Vector *v3);

/* Vector */
Vector *uNewVector(double x, double y);
double unormalize_angle(double x);
double udistance_sq(Vector *a, Vector *b);
double uVector_length(Vector *v);
double udot(Vector *v1, Vector *v2);
double uangle_between(Vector *v1, Vector *v2);

/* Polygon/Rect */
Rect *uNewRect(double x, double y, double w, double h);
PyObject *unormalize_poly(PyObject *poly, int wrap);
Vector *ucentroid(PyObject *seq);
int upoint_in(Vector *point, PyObject *poly);
double usigned_area(PyObject *poly);
void uproject_to(Polygon *poly, Vector *axis, Projection *projection);
int uprojections_intersect(Projection *a, Projection *b);
void unormperp(Vector *v);
int upolys_intersect(Polygon *a, Polygon *b);

/* -------- CONVERSION -------- */
Vector *Vector_FromObject(PyObject *obj);
Polygon *Polygon_FromObject(PyObject *obj);

/* -------- FLMATH FUNCTIONS -------- */
/* Generic Functions */
PyObject *closest_pow2(PyObject *self, PyObject *args);
PyObject *next_pow2(PyObject *self, PyObject *args);
PyObject *prev_pow2(PyObject *self, PyObject *args);
PyObject *normalize_angle(PyObject *self, PyObject *args);
PyObject *normalize_angler(PyObject *self, PyObject *args);
/* Linear Functions */
PyObject *distance(PyObject *self, PyObject *args);
PyObject *distance_sq(PyObject *self, PyObject *args);
PyObject *midpoint(PyObject *self, PyObject *args);
/* Vector Functions */
PyObject *dot(PyObject *self, PyObject *args);
PyObject *angle_between(PyObject *self, PyObject *args);
/* Polygon Functions */
PyObject *normalize_poly(PyObject *self, PyObject *args);
PyObject *point_in(PyObject *self, PyObject *args);
PyObject *centroid(PyObject *self, PyObject *args);
PyObject *area(PyObject *self, PyObject *args);
PyObject *signed_area(PyObject *self, PyObject *args);
PyObject *orientation_poly(PyObject *self, PyObject *args);
PyObject *simplify_poly(PyObject *self, PyObject *args);
void dp_recur(double tol2, Vector **L, int j, int k, int *mk);

/* -------- VECTOR METHODS -------- */
int Vector_Check(PyObject *obj);
/* Initialization */
void Vector_dealloc(Vector *self);
PyObject *Vector_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
int Vector_init(Vector *self, PyObject *args);
PyObject *Vector_reduce(Vector *self);
/* Presentation */
PyObject *Vector_repr(Vector *self);
PyObject *Vector_str(Vector *self);
/* Comparison */
PyObject *Vector_richcompare(PyObject *a, PyObject *b, int op);
/* Sequence Operations */
Py_ssize_t Vector_len(Vector *self);
PyObject *Vector_item(Vector *self, Py_ssize_t i);
int Vector_ass_item(Vector *self, Py_ssize_t i, PyObject *value);
/* Generic Number Operations */
Vector *Vector_oper(Vector *a, Vector *b, int oper);
void Vector_ioper(Vector *a, Vector *b, int oper);
PyObject *Vector_pos(Vector *self);
PyObject *Vector_neg(Vector *self);
PyObject *Vector_abs(Vector *self);
int Vector_nonzero(Vector *self);
/* Arithmetic Operations */
PyObject *Vector_add(PyObject *a, PyObject *b);
PyObject *Vector_iadd(Vector *a, PyObject *b);
PyObject *Vector_sub(PyObject *a, PyObject *b);
PyObject *Vector_isub(Vector *a, PyObject *b);
PyObject *Vector_mul(PyObject *a, PyObject *b);
PyObject *Vector_imul(Vector *a, PyObject *b);
PyObject *Vector_div(PyObject *a, PyObject *b);
PyObject *Vector_idiv(Vector *a, PyObject *b);
PyObject *Vector_flr(PyObject *a, PyObject *b);
PyObject *Vector_iflr(Vector *a, PyObject *b);
PyObject *Vector_mod(PyObject *a, PyObject *b);
PyObject *Vector_imod(Vector *a, PyObject *b);
PyObject *Vector_pow(PyObject *a, PyObject *b);
/* Generic Functions */
PyObject *Vector_copy(Vector *self);
PyObject *Vector_update(Vector *self, PyObject *args);
PyObject *Vector_dot(Vector *self, PyObject *args);
PyObject *Vector_normalize(Vector *self);
PyObject *Vector_rotate(Vector *self, PyObject *args);
PyObject *Vector_perpendicular(Vector *self);
PyObject *Vector_angle_about(Vector *self, PyObject *args);
PyObject *Vector_angle_between(Vector *self, PyObject *args);
/* Properties */
PyObject *Vector_getx(Vector *self, void *closure);
int Vector_setx(Vector *self, PyObject *value, void *closure);
PyObject *Vector_gety(Vector *self, void *closure);
int Vector_sety(Vector *self, PyObject *value, void *closure);
/* length */
PyObject *Vector_getlength(Vector *self, void *closure);
int Vector_setlength(Vector *self, PyObject *value, void *closure);
/* angle */
PyObject *Vector_getangle(Vector *self, void *closure);
int Vector_setangle(Vector *self, PyObject *value, void *closure);

/* -------- POLYGON METHODS -------- */
int Polygon_Check(PyObject *obj);
/* Initialization */
void Polygon_dealloc(Polygon *self);
PyObject *Polygon_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
int Polygon_init(Polygon *self, PyObject *args);
PyObject *Polygon_setcache(Polygon *self, PyObject *args);
PyObject *Polygon_reduce(PyObject *self);
PyObject *Polygon_enableflag(Polygon *self, PyObject *args);
PyObject *Polygon_disableflag(Polygon *self, PyObject *args);
PyObject *Polygon_flagenabled(Polygon *self, PyObject *args);
/* Presentation */
PyObject *Polygon_repr(Polygon *self);
PyObject *Polygon_str(Polygon *self);
/* Comparison */
PyObject *Polygon_richcompare(PyObject *a, PyObject *b, int op);
/* Sequence Operations */
Py_ssize_t Polygon_len(Polygon *self);
PyObject *Polygon_item(Polygon *self, Py_ssize_t i);
PyObject *Polygon_node(Polygon *self, PyObject *args);
void Polygon_reposition(Polygon *self);
int Polygon_ass_item(Polygon *self, Py_ssize_t i, PyObject *value);
PyObject *Polygon_append(Polygon *self, PyObject *args);
PyObject *Polygon_insert(Polygon *self, PyObject *args);
PyObject *Polygon_remove(Polygon *self, PyObject *args);
/* Generic Functions */
PyObject *Polygon_copy(Polygon *self);
PyObject *Polygon_get_points(Polygon *self);
PyObject *Polygon_point_in(Polygon *self, PyObject *args);
PyObject *Polygon_project_to(Polygon *self, PyObject *args);
PyObject *Polygon_angle_about(Polygon *self, PyObject *args);
PyObject *Polygon_intersects(Polygon *self, PyObject *args);
/* Properties */
PyObject *Polygon_getcenter(Polygon *self, void *closure);
int Polygon_setcenter(Polygon *self, PyObject *value, void *closure);
PyObject *Polygon_getcenterx(Polygon *self, void *closure);
int Polygon_setcenterx(Polygon *self, PyObject *value, void *closure);
PyObject *Polygon_getcentery(Polygon *self, void *closure);
int Polygon_setcentery(Polygon *self, PyObject *value, void *closure);
PyObject *Polygon_getarea(Polygon *self, void *closure);
PyObject *Polygon_getsarea(Polygon *self, void *closure);
PyObject *Polygon_getangle(Polygon *self, void *closure);
int Polygon_setangle(Polygon *self, PyObject *value, void *closure);
PyObject *Polygon_getorientation(Polygon *self, void *closure);
int Polygon_setorientation(Polygon *self, PyObject *value, void *closure);

/* -------- RECT METHODS -------- */
/* Initialization */
void Rect_dealloc(Rect *self);
PyObject *Rect_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
int Rect_init(Rect *self, PyObject *args);
PyObject *Rect_calculate_corners(Rect *self);
PyObject *Rect_reduce(PyObject *self);
/* Presentation */
PyObject *Rect_repr(Rect *self);
PyObject *Rect_str(Rect *self);
/* Sequence Operations */
PyObject *Rect_item(Rect *self, Py_ssize_t i);
int Rect_ass_item(Rect *self, Py_ssize_t i, PyObject *value);
/* Generic Functions */
PyObject *Rect_copy(Rect *self);
/* Properties */
/* Edges */
PyObject *Rect_gettop(Rect *self, void *closure);
int Rect_settop(Rect *self, PyObject *value, void *closure);
PyObject *Rect_getbottom(Rect *self, void *closure);
int Rect_setbottom(Rect *self, PyObject *value, void *closure);
PyObject *Rect_getleft(Rect *self, void *closure);
int Rect_setleft(Rect *self, PyObject *value, void *closure);
PyObject *Rect_getright(Rect *self, void *closure);
int Rect_setright(Rect *self, PyObject *value, void *closure);
/* Corners */
PyObject *Rect_gettopleft(Rect *self, void *closure);
int Rect_settopleft(Rect *self, PyObject *value, void *closure);
PyObject *Rect_getbottomleft(Rect *self, void *closure);
int Rect_setbottomleft(Rect *self, PyObject *value, void *closure);
PyObject *Rect_gettopright(Rect *self, void *closure);
int Rect_settopright(Rect *self, PyObject *value, void *closure);
PyObject *Rect_getbottomright(Rect *self, void *closure);
int Rect_setbottomright(Rect *self, PyObject *value, void *closure);
/* Midpoints */
PyObject *Rect_getmidtop(Rect *self, void *closure);
int Rect_setmidtop(Rect *self, PyObject *value, void *closure);
PyObject *Rect_getmidbottom(Rect *self, void *closure);
int Rect_setmidbottom(Rect *self, PyObject *value, void *closure);
PyObject *Rect_getmidleft(Rect *self, void *closure);
int Rect_setmidleft(Rect *self, PyObject *value, void *closure);
PyObject *Rect_getmidright(Rect *self, void *closure);
int Rect_setmidright(Rect *self, PyObject *value, void *closure);
/* Dimensions */
PyObject *Rect_getwidth(Rect *self, void *closure);
int Rect_setwidth(Rect *self, PyObject *value, void *closure);
PyObject *Rect_getheight(Rect *self, void *closure);
int Rect_setheight(Rect *self, PyObject *value, void *closure);
PyObject *Rect_getsize(Rect *self, void *closure);
int Rect_setsize(Rect *self, PyObject *value, void *closure);

PyMODINIT_FUNC initflmath(void);
